package com.blue.integration.serve.local;

import com.blue.core.id.IdGenerator;
import com.blue.core.util.UrlUtil;
import com.blue.integration.serve.Bucket;
import com.blue.integration.serve.StorageClient;
import com.blue.integration.serve.StorageException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;

import java.io.*;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Scanner;

/**
 * 本地文件存储
 *
 * @author zhengjin
 * @since 1.0 2017年11月15日
 */
public class LocalStorageClient implements StorageClient, InitializingBean
{
	private static Logger logger = LoggerFactory.getLogger(LocalStorageClient.class);
	public final static DateTimeFormatter KEY_FORMATTER = DateTimeFormatter.ofPattern("yyyyMMdd");

	private String root;
	private String prefix;

	public LocalStorageClient()
	{
	}

	@Override
	public String save(Bucket bucket, File file, String key) throws IOException
	{
		Assert.notNull(file, "文件不能为空");
		return this.save(bucket, new FileInputStream(file), file.getName(), key);
	}

	@Override
	public String save(Bucket bucket, InputStream is, String name, String key) throws IOException
	{
		if (bucket == null)
			throw new StorageException("bucket 不能为空");

		Assert.notNull(is, "输入流不能为空");
		Assert.notNull(name, "原始文件名称不能为空");
		if (key == null || key.isEmpty())
		{
			key = this.getKey(name);
		}
		String path = this.getPath(bucket, File.separatorChar, key, root, null);
		File dest = new File(path);
		if (!dest.getParentFile().exists())
		{
			if (!dest.getParentFile().mkdirs())
				throw new StorageException("无法创建目录：" + dest.getParent());
		}

		try (InputStream iis = is;
			FileOutputStream fos = new FileOutputStream(dest))
		{
			IOUtils.copyLarge(iis, new FileOutputStream(dest));
		}
		logger.info("成功上传文件：{}", key);
		return key;
	}

	@Override
	public void delete(Bucket bucket, String key)
	{
		String path = this.getPath(bucket, File.separatorChar, key, root, null);
		FileUtils.deleteQuietly(new File(path));
		logger.info("成功删除文件：{}", key);
	}

	@Override
	public File download(Bucket bucket, String key, File dest) throws IOException
	{
		String path = this.getPath(bucket, File.separatorChar, key, root, null);
		if (dest == null)
		{
			String ext = UrlUtil.getFileExt(key);
			String p = UrlUtil.getTempDir() + IdGenerator.uuid12bit() + ext;
			dest = new File(p);
		}
		try (FileInputStream fis = new FileInputStream(path);
		     FileOutputStream fos = new FileOutputStream(dest))
		{
			IOUtils.copyLarge(fis, fos);
		}
		logger.info("成功下载文件：{}", key);
		return dest;
	}

	@Override
	public InputStream getStream(Bucket bucket, String key) throws IOException
	{
		String path = this.getPath(bucket, File.separatorChar, key, root, null);
		return new FileInputStream(path);
	}

	@Override
	public String getString(Bucket bucket, String key) throws IOException
	{
		String path = this.getPath(bucket, File.separatorChar, key, root, null);
		StringBuilder str = new StringBuilder(4096);
		try (Scanner scanner = new Scanner(new File(path), "UTF-8");)
		{
			while (scanner.hasNextLine())
			{
				str.append(scanner.nextLine()).append("\n");
			}
		}
		return str.toString();
	}

	@Override
	public String getUrl(Bucket bucket, String key)
	{
		if (key == null || key.isEmpty())
			return null;

		return this.getPath(bucket, '/', key, null, prefix);
	}

	@Override
	public String getKey(String name)
	{
		String ext = UrlUtil.getFileExt(name);
		StringBuilder key = new StringBuilder(32);
		key.append(KEY_FORMATTER.format(LocalDate.now()));
		key.append("_");
		key.append(IdGenerator.uuid16bit());
		key.append(ext);
		return key.toString();
	}

	public void setRoot(String root)
	{
		this.root = root;
		logger.info("本地存储根目录：{}", this.root);
	}

	public void setPrefix(String prefix)
	{
		if (prefix != null && !prefix.isEmpty())
		{
			if (prefix.startsWith("/"))
				this.prefix = prefix;
			else
				this.prefix = "/" + prefix;
		}

		logger.info("本地存储前缀：{}", this.prefix);
	}

	private String getPath(Bucket bucket, char sep, String key, String root, String prefix)
	{
		if (bucket == null)
			throw new StorageException("bucket 不能为空");

		Assert.hasText(key, "Key 不能为空");

		String year = key.substring(0, 4);
		String month = key.substring(4, 6);
		String day = key.substring(6, 8);

		StringBuilder url = new StringBuilder(32);
		if (root != null && !root.isEmpty())
		{
			url.append(root);
		}
		if (prefix != null && !prefix.isEmpty())
		{
			url.append(prefix);
		}
		url.append(sep);
		url.append(bucket.name().toLowerCase());
		url.append(sep).append(year);
		url.append(sep).append(month);
		url.append(sep).append(day);
		url.append(sep).append(key);
		return url.toString();
	}

	@Override
	public void afterPropertiesSet() throws Exception
	{
		if (root == null || root.isEmpty())
			throw new StorageException("root 不能为空");

	}
}
